#include "protocol_analyzer_impl.hh"
#include "../corelib/util/string_util.hh"
#include "../corelib/network/parameter.hh"

#ifdef WIN32
#include <WinSock2.h>
#else
#include <arpa/inet.h>
#endif

namespace kratos { namespace engine {

ProtocolAnalyzerImpl::ProtocolAnalyzerImpl()
    : headerSize_(0), includeHeader_(false), lenghPos_(0), lengthBytes_(0), parsed_(false) {
}

ProtocolAnalyzerImpl::~ProtocolAnalyzerImpl() {
}

static bool check(const std::string& s) {
    if (s.empty()) {
        return false;
    }
    for (std::size_t i = 0; i < s.size(); i++) {
        if (i + 1 == s.size()) {
            if (!(isdigit(s[i]) || (s[i] == 'l' || s[i] == 'L'))) {
                return false;
            }
        } else {
            if (!isdigit(s[i])) {
                return false;
            }
        }
    }
    return true;
}

bool ProtocolAnalyzerImpl::setAnalyzer(const std::string & analyzer) {
    if (analyzer.empty()) {
        return false;
    }
    std::vector<std::string> result;
    corelib::StringUtil::split(analyzer, ":", result);
    bool flag = false;
    for (auto& s : result) {
        if (!check(s)) {
            return false;
        }
        if (corelib::StringUtil::endWith(s, "l")) {
            if (flag) {
                return false;
            }
            flag = true;
            auto lengthBytes = std::stoi(corelib::StringUtil::remove(s, "l"));
            headerSize_ += lengthBytes;
            lengthBytes_ = lengthBytes;
            includeHeader_ = false;
        } else if (corelib::StringUtil::endWith(s, "L")) {
            if (flag) {
                return false;
            }
            flag = true;
            auto lengthBytes = std::stoi(corelib::StringUtil::remove(s, "L"));
            headerSize_ += lengthBytes;
            lengthBytes_ = lengthBytes;
            includeHeader_ = true;
        } else {
            if (!flag) {
                lenghPos_ += std::stoi(s);
            }
            headerSize_ += std::stoi(s);
        }
    }
    if ((lengthBytes_ != 2) && (lengthBytes_ != 4)) {
        return false;
    }
    parsed_ = true;
    return true;
}

bool ProtocolAnalyzerImpl::hasFullPacket(network::SessionReader& reader, std::size_t& size) {
    size = reader.available();
    if (headerSize_ > size) {
        size = 0;
        return false;
    }
    std::uint32_t length = 0;
    char data[NETWORK_SESSION_RECV_BUFFER_MAX_SIZE] = { 0 };
    reader.copy(data, headerSize_);
    memcpy(&length, data + lenghPos_, lengthBytes_);
    if (lengthBytes_ == 4) {
        length = ntohl(length);
    } else {
        length = ntohs(static_cast<std::uint16_t>(length));
    }
    if (!length) {
        size = 0;
        return false;
    }
    if (includeHeader_) {
        if (length > size) {
            size = 0;
            return false;
        }
        size = length;
    } else {
        auto restSize = size - headerSize_;
        if (length > restSize) {
            size = 0;
            return false;
        }
        size = length + headerSize_;
    }
    return true;
}

bool ProtocolAnalyzerImpl::isParsed() {
    return parsed_;
}

}}
